/*
 *     This file is part of Mobile GPS Logger.
 * 
 *     Mobile GPS Logger is free software: you can redistribute it and/or
 *     modify it under the terms of the GNU General Public License as
 *     published by the Free Software Foundation, either version 3 of the
 *     License, or (at your option) any later version.
 * 
 *     Mobile GPS Logger is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License v3 for more details.
 * 
 *     You should have received a copy of the GNU General Public License v3
 *     along with Mobile GPS Logger. If not, see <http://www.gnu.org/licenses/>.
 */


package cx.ath.skyflyer.gpslog;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Stack;
import java.util.Vector;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import javax.microedition.lcdui.*;

/**
 *
 * @author Ahti Legonkov
 */
public class FileList extends Canvas {

    public FileList(String path, String title) {
        try {
            setFullScreenMode(true);
            setPath(path);
            setTitle(title);
        }
        catch (IOException ex) {
            // TODO: something
        }
    }

    /**
     * 
     * @param listener
     */
    //public void setListener(CommandListener listener) {
        //listener.commandAction(CMD_FILE_SELECTED, this);
    //}

    private void setPath(String path) throws IOException {
        setPath(path, 0, 0);
    }
    
    /**
     *
     * @param path
     * @param selected
     * @param first
     * @throws java.io.IOException
     */
    private void setPath(String path, int selected, int first) throws IOException {
        m_path = path;
        m_selected = selected;
        m_first = first;
        refreshFileList();
    }

    /**
     * Checks if given name is a directory or a file.
     * @param filePath full path to a directory or a file.
     * @return true if path is to a directory, false if the path is to a file.
     */
    private static boolean isDirectory(String filePath) {
        return filePath.endsWith("/");
    }

    private void refreshFileList() throws IOException {
        FileConnection fc = (FileConnection)Connector.open(m_path);
        Enumeration en = fc.list();

        m_files = new Vector();
        if (m_path.length() > 11) // file:///x:/
            m_files.addElement(new Item("..", true));

        while (en.hasMoreElements()) {
            String fileName = (String)en.nextElement();
            String filePath = m_path+fileName;
            m_files.addElement(new Item(fileName, isDirectory(filePath)));
        }

        this.repaint();
    }

    /**
     *
     */
    private static class Item
    {
        /**
         *
         * @param name
         * @param isDirectory
         */
        public Item(String name, boolean isDirectory) {
            this.name = name;
            this.dir = isDirectory;
        }

        /**
         *
         * @return
         */
        public String getFilename() { return name; }

        /**
         *
         * @return
         */
        public boolean isDirectory() { return dir; }

        public String toString() { return name; }
        
        private final String name;
        private final boolean dir;
    }

    /**
     * 
     */
    private static class StackItem {

        StackItem(int selected, int first) {
            this.selected = selected;
            this.first = first;
        }
        
        public final int selected;
        public final int first;
    }

    /**
     * 
     * @param g
     */
    protected void paint(Graphics g) {

        Font font = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_LARGE);

        final int width = getWidth();
        final int height = getHeight() - font.getHeight();

        int top = 0;
        // clear background
        g.setFont(font);
        g.setColor(255, 255, 255);
        g.fillRect(0, 0, width, height);

        // draw title
        g.setColor(0, 0, 0);
        g.drawString(getTitle(), width/2, 0, Graphics.TOP | Graphics.HCENTER);
        final int y = font.getHeight()+2;
        g.drawLine(0, y, width, y);

        top += font.getHeight() + 4;
        if (m_itemsTop < 0)
            m_itemsTop = top;

        // draw list of files.
        font = Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_SMALL);
        g.setFont(font);
        
        if (m_itemHeight < 0)
            m_itemHeight = font.getHeight() + 3;
        
        for (int i = m_first; i < m_files.size(); ++i) {
            final Item it = (Item)m_files.elementAt(i);
            final String filename = it.getFilename();
            if (i == m_selected) {
                g.setColor(192, 192, 229);
                g.fillRect(0, top-1, width, font.getHeight()+2);
                g.setColor(0, 0, 0);
            }
            g.drawString(filename, 10, top, Graphics.TOP | Graphics.LEFT);
            top += m_itemHeight;
            if (top >= height)
                break;
        }

        // draw commands
        g.drawLine(0, height, width, height);
        g.drawString("Select", width/2, getHeight(), Graphics.BOTTOM | Graphics.HCENTER);
        g.drawString("Back", width, getHeight(), Graphics.BOTTOM | Graphics.RIGHT);
    }

    public void setCommandListener(CommandListener l) {
        super.setCommandListener(l);
        m_listener = l;
    }

    protected void keyRepeated(int keyCode) {
        super.keyRepeated(keyCode);
        keyPressed(keyCode);
    }


    protected void keyPressed(int keyCode) {

        final int gameAction = getGameAction(keyCode);
        final int itemCount = (getHeight() - m_itemsTop) / m_itemHeight;

        switch (gameAction) {
        case UP:
            if (m_selected > 0) {
                --m_selected;
                if (m_selected < m_first)
                    --m_first;
            }
            break;

        case DOWN:
            if (m_selected+1 < m_files.size()) {
                ++m_selected;
                if (m_selected - m_first >= itemCount)
                    ++m_first;
            }
            break;

        case LEFT:
            m_selected = 0;
            m_first = 0;
            break;

        case RIGHT:
            m_selected = m_files.size()-1;
            m_first = m_files.size()-1-itemCount;
            if (m_first < 0)
                m_first = 0;
            break;

        case FIRE: // select
            {
                Item i = (Item)m_files.elementAt(m_selected);
                if (i.isDirectory()) {
                    try {
                        final String fn = i.getFilename();
                        if (fn.equals("..")) {
                            final int idx = m_path.lastIndexOf('/', m_path.length()-2);
                            if (idx > 0) {
                                int s = 0;
                                int f = 0;
                                if (!m_stack.empty()) {
                                    final StackItem si = (StackItem)m_stack.pop();
                                    s = si.selected;
                                    f = si.first;
                                }

                                setPath(m_path.substring(0, idx+1), s, f);
                            }
                        }
                        else {
                            m_stack.push(new StackItem(m_selected, m_first));
                            setPath(m_path + i.getFilename());
                        }
                        return;
                    }
                    catch (IOException ex) {
                        
                    }
                }
                else if (m_listener != null)
                    m_listener.commandAction(CMD_FILE_SELECTED, this);
                
                return;
            }

        case GAME_A: System.out.println("GAME_A"); break;
        case GAME_B: System.out.println("GAME_B"); break;
        case GAME_C: System.out.println("GAME_C"); break;
        case GAME_D: System.out.println("GAME_D"); break;
        default:

            System.out.println("Key code: "+keyCode);
            if (m_listener != null) {
                switch (keyCode) {
                    //case -6: m_listener.commandAction(CMD_, this); break;
                    case -7: m_listener.commandAction(CMD_BACK, this); break;
                }
            }
            return;
        }

        repaint();
    }

    public String getSelectedFilePath() {
        return m_path + m_files.elementAt(m_selected);
    }


    private Vector m_files;
    private final Stack m_stack = new Stack();
    private int m_selected = 0;
    private int m_first = 0;
    private int m_itemHeight = -1;
    private int m_itemsTop = -1;
    private CommandListener m_listener = null;
    private String m_path = "";

    public static final Command CMD_FILE_SELECTED = new Command("Select", Command.OK, 0);
    public static final Command CMD_BACK = new Command("Back", Command.BACK, 0);
}
